﻿using Autofac.Builder;
using Autofac;
using System.Reflection;
using Common.Mef.Attributes;
using Common.Mef.Enums;
using Microsoft.Extensions.DependencyInjection;
using Autofac.Extensions.DependencyInjection;

namespace Common.Mef
{
    public static class Mef
    {
        #region 属性  
        public static IContainer Current { get; set; }
        private static readonly string AppExecuteRootDir;//程序执行主目录，对于网站就是BIN。
        public static HashSet<string> ExportedDlls;

        private static readonly HashSet<string> LocalImplementInterfaces;


        #endregion

        #region 构造

        /// <summary>
        /// 静态构造函数
        /// </summary>
        static Mef()
        {
            LocalImplementInterfaces = new HashSet<string>();
            AppExecuteRootDir = AppDomain.CurrentDomain.BaseDirectory;
            ExportedDlls = new HashSet<string>();
        }

        #endregion

        /// <summary>
        /// 完成初始化只能build一次 所以将这个状态设置放出来供业务判断是否需要再此之前进行服务注入
        /// </summary>
        public static IContainer Compelted(this ContainerBuilder bulider)
        {
            Current = bulider.Build();
            return Current;
        }

        /// <summary>
        /// 是否本地实现的接口
        /// </summary>
        /// <param name="interfaceFullName"></param>
        /// <returns></returns>
        public static bool IsLocalImplementInterfaces(string interfaceFullName)
        {
            return LocalImplementInterfaces.Contains(interfaceFullName);
        }

        #region 初始化     

        public static ContainerBuilder AddByFilterPattern(this ContainerBuilder builder, string assemblyFilterPattern)
        {
            AddByFilterPattern(assemblyFilterPattern);
            return builder;
        }

        public static ContainerBuilder AddByDir(this ContainerBuilder builder, string relativePath)
        {
            AddByDir(relativePath);
            return builder;
        }
        /// <summary>
        /// 初始化容器 
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="services">自带的服务</param>
        public static ContainerBuilder AddMefContainer(this ContainerBuilder builder, IServiceCollection? services = null)
        {
            if (builder == null)
            {
                throw new Exception("容器不能为空！");
            }
            if (services != null)//和自带的DI合并
            {
                builder.Populate(services);
            }

            //将导出的dll加载到当前应用程序域
            foreach (var exportedDll in ExportedDlls)
            {
                var assembly = Assembly.LoadFrom(exportedDll);
                AppDomain.CurrentDomain.Load(assembly.FullName);
            }
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assembly in assemblies)
            {
                try
                {
                    var types = assembly.GetTypes();
                    foreach (var classType in types)
                    {

                        var attributes = classType.GetCustomAttributes().ToList();
                        if (attributes.Count == 0)
                        {
                            continue;
                        }

                        //添加服务事件映射
                        //AddServiceEventMap(classType, attributes);

                        var exportAttributes = attributes.Where(attribute => attribute is CustomInjectionAttribute).OfType<CustomInjectionAttribute>().ToList();
                        if (exportAttributes.Count == 0)
                        {
                            continue;
                        }
                        var partCreationPolicy = classType.GetCustomAttribute<PartCreationPolicyAttribute>();

                        var creationPolicy = CreationPolicy.SingleInstance;
                        if (partCreationPolicy != null)
                        {
                            creationPolicy = partCreationPolicy.CreationPolicy;
                        }

                        bool multiTypesSingleInstance = exportAttributes.Count > 1;
                        if (!multiTypesSingleInstance)
                        {
                            builder.RegisterBySingleAttribute(exportAttributes[0], classType, creationPolicy);
                            continue;
                        }
                        builder.RegisterMultiAttributes(exportAttributes, classType, creationPolicy);
                    }

                }
                catch (Exception e)
                {
                    if (e is ReflectionTypeLoadException exception && exception.LoaderExceptions != null)
                    {
                        foreach (var exceptionLoaderException in exception.LoaderExceptions)
                        {
                            Console.WriteLine($"解析内联错误：{exceptionLoaderException.Message}");
                        }
                    }
                    Console.WriteLine($"dll加载错误：{e.Message}");
                }
            }
            return builder;
        }


        /// <summary>
        /// 注册多个导出属性
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="exportAttributes"></param>
        /// <param name="classType"></param>
        /// <param name="creationPolicy"></param>
        private static void RegisterMultiAttributes(this ContainerBuilder builder, List<CustomInjectionAttribute> exportAttributes, Type classType, CreationPolicy creationPolicy)
        {
            IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle> instance = null;
            foreach (var exportAttribute in exportAttributes)
            {
                var interfaceType = exportAttribute.ContractType;
                if (interfaceType == null)
                {
                    interfaceType = classType;
                }
                LocalImplementInterfaces.Add(interfaceType.FullName);
                if (!string.IsNullOrEmpty(exportAttribute.ContractName))
                {
                    instance = instance == null ? builder.RegisterType(classType).Keyed(exportAttribute.ContractName, interfaceType) : instance.Keyed(exportAttribute.ContractName, interfaceType);
                }
                else
                {
                    instance = instance == null ? builder.RegisterType(classType).As(interfaceType) : instance.As(interfaceType);
                }
            }

            if (creationPolicy == CreationPolicy.InstancePerDependency)
            {
                instance?.InstancePerDependency();
            }
            else if (creationPolicy == CreationPolicy.InstancePerLifetimeScope)
            {
                instance?.InstancePerLifetimeScope();
            }
            else
            {
                instance?.SingleInstance();
            }

        }

        /// <summary>
        /// 注册单个Export
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="exportAttribute"></param>
        /// <param name="classType"></param>
        /// <param name="creationPolicy"></param>
        private static void RegisterBySingleAttribute(this ContainerBuilder builder, CustomInjectionAttribute exportAttribute, Type classType, CreationPolicy creationPolicy)
        {
            Type interfaceType = exportAttribute.ContractType;
            if (interfaceType == null)
            {
                interfaceType = classType;
            }
            LocalImplementInterfaces.Add(interfaceType.FullName);
            if (creationPolicy == CreationPolicy.InstancePerDependency)
            {
                if (!string.IsNullOrEmpty(exportAttribute.ContractName))
                {
                    builder.RegisterType(classType).Keyed(exportAttribute.ContractName, interfaceType).InstancePerDependency();
                    return;
                }
                builder.RegisterType(classType).As(interfaceType).InstancePerDependency();
                return;
            }
            if (!string.IsNullOrEmpty(exportAttribute.ContractName))
            {
                builder.RegisterType(classType).Keyed(exportAttribute.ContractName, interfaceType).SingleInstance();
                return;
            }
            builder.RegisterType(classType).As(interfaceType).SingleInstance();
        }


        /// <summary>
        /// 在运行根目录搜索符合表达式的DLL
        /// </summary>
        /// <param name="relativePath">程序集筛选表达式，如"*.ClientProxy.dll"</param>
        public static void AddByDir(string relativePath)
        {
            string directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, relativePath);
            if (!Directory.Exists(directory))
            {
                Console.WriteLine($"扫描dll目录[{directory}]不存在");
                return;
            }
            //var dllPaths = Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories).Where(x => x.ToLower().EndsWith("*.dll"));
            var dllPaths = Directory.GetFiles(directory, "*.dll", SearchOption.AllDirectories);//.Where(x => x.ToLower().EndsWith("*.dll"));
            foreach (var dllPath in dllPaths)
            {
                ExportedDlls.Add(dllPath);
            }
        }

        public static void ExceptDll(string relativePath)
        {
            string dll = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, relativePath);
            ExportedDlls.Remove(dll);
        }


        /// <summary>
        /// 在运行根目录搜索符合表达式的DLL
        /// </summary>
        /// <param name="assemblyFilterPattern">程序集筛选表达式，如"*.ClientProxy.dll"</param>
        public static void AddByFilterPattern(string assemblyFilterPattern)
        {
            AddByFilterPattern(new List<string>() { assemblyFilterPattern });
        }

        /// <summary>
        /// 在运行根目录搜索符合表达式的DLL
        /// </summary>
        /// <param name="assemblyFilterPatterns">程序集筛选表达式，如"*.ClientProxy.dll"</param>
        public static void AddByFilterPattern(List<string> assemblyFilterPatterns)
        {
            if (assemblyFilterPatterns != null)
            {
                //扫描所有程序集，反射注册命令
                var exeDir = new DirectoryInfo(AppExecuteRootDir);

                assemblyFilterPatterns.ForEach(s =>
                {
                    //搜索根目录
                    FileInfo[] executorDlls = exeDir.GetFiles(s);

                    //处理目录下程序集
                    if (executorDlls.Length > 0)
                    {
                        executorDlls.ToList().ForEach(
                            dll =>
                            {
                                ExportedDlls.Add(dll.FullName);
                            }
                        );
                    }
                });
            }
        }

        #endregion

        #region 获取实例    


        public static T GetExportedValue<T>()
        {
            return Current.Resolve<T>();
        }

        public static IEnumerable<T> GetExportedValues<T>()
        {
            return Current.Resolve<IEnumerable<T>>();
        }

        public static IEnumerable<T> GetExportedValues<T>(string key)
        {
            return Current.ResolveKeyed<IEnumerable<T>>(key);
        }

        /// <summary>
        /// 注意释放
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T GetExportedValue<T>(string key)
        {
            //var obj = CustomContainer.GetService(typeof(T), key);
            //if (obj != null)
            //{
            //    return (T)obj;
            //}
            return Current.ResolveKeyed<T>(key);
        }

        /// <summary>
        /// 注意释放
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object GetExportedValue(Type type)
        {
            return Current.Resolve(type);
        }

        public static object GetExportedValue(string key, Type type)
        {
            return Current.ResolveKeyed(key, type);
        }

        #endregion

        #region 初始化   

        /// <summary>
        /// 注册实例，每调用一次 实例化一次
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TInterface"></typeparam>
        /// <param name="builder"></param>
        public static void Register<TImplementation, TInterface>(this ContainerBuilder builder)
        {
            builder.RegisterType<TImplementation>().As<TInterface>().InstancePerDependency();
        }

        /// <summary>
        /// 注册实例，每调用一次 实例化一次
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TInterface"></typeparam>
        /// <param name="builder"></param>
        /// <param name="key">服务关键字</param>
        public static void Register<TImplementation, TInterface>(this ContainerBuilder builder, object key)
        {
            builder.RegisterType<TImplementation>().Keyed<TInterface>(key).InstancePerDependency();
        }

        /// <summary>
        /// 注册成单例
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TInterface"></typeparam>
        /// <param name="builder"></param>        
        public static void RegisterSingleInstance<TImplementation, TInterface>(this ContainerBuilder builder)
        {
            builder.RegisterType<TImplementation>().As<TInterface>().SingleInstance();
        }

        /// <summary>
        /// 注册成单例
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <param name="builder"></param>        
        public static void RegisterSingleInstance<TImplementation>(this ContainerBuilder builder)
        {
            builder.RegisterType<TImplementation>().As<TImplementation>().SingleInstance();
        }

        /// <summary>
        /// 注册成单例
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TInterface"></typeparam>
        /// <param name="builder"></param>
        /// <param name="key">服务关键字</param>
        public static void RegisterSingleInstance<TImplementation, TInterface>(this ContainerBuilder builder, object key)
        {
            builder.RegisterType<TImplementation>().Keyed<TInterface>(key).SingleInstance();
        }

        /// <summary>
        /// 注册实例，PerLifetime实例化一次
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TInterface"></typeparam>
        /// <param name="builder"></param>
        public static void RegisterPerLifetimeScope<TImplementation, TInterface>(this ContainerBuilder builder)
        {
            builder.RegisterType<TImplementation>().As<TInterface>().InstancePerLifetimeScope();
        }

        /// <summary>
        /// 注册实例，PerLifetime实例化一次
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TInterface"></typeparam>
        /// <param name="builder"></param>
        /// <param name="key">服务关键字</param>
        public static void RegisterPerLifetimeScope<TImplementation, TInterface>(this ContainerBuilder builder, object key)
        {
            builder.RegisterType<TImplementation>().Keyed<TInterface>(key).InstancePerLifetimeScope();
        }

        /// <summary>
        /// 覆盖注册
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TInterface"></typeparam>
        /// <param name="builder"></param>  
        /// <param name="key">服务关键字</param>
        public static void RegisterOverride<TImplementation, TInterface>(this ContainerBuilder builder)
        {
            builder.RegisterType<TImplementation>().As<TInterface>().PreserveExistingDefaults();
        }


        /// <summary>
        /// 覆盖注册
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TInterface"></typeparam>
        /// <param name="builder"></param>
        /// <param name="key">服务关键字</param>
        public static void RegisterOverride<TImplementation, TInterface>(this ContainerBuilder builder, string key)
        {
            builder.RegisterType<TImplementation>().Keyed<TInterface>(key).PreserveExistingDefaults();
        }

        #endregion

        #region 获取实例    


        public static T GetService<T>()
        {
            return Current.Resolve<T>();
        }

        /// <summary>
        /// 获取LifeTimeScope
        /// </summary>
        /// <returns></returns>
        public static ILifetimeScope GetLifeTimeScope()
        {
            return Current.BeginLifetimeScope();
        }

        /// <summary>
        ///是否注册
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static bool IsRegistered<T>()
        {
            return Current.IsRegistered<T>();
        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool IsRegistered<T>(string key)
        {
            return Current.IsRegisteredWithKey<T>(key);
        }

        public static bool IsRegistered(Type type)
        {
            return Current.IsRegistered(type);
        }

        public static bool IsRegisteredWithKey(string key, Type type)
        {
            return Current.IsRegisteredWithKey(key, type);
        }

        /// <summary>
        /// 注意释放
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T GetService<T>(string key)
        {
            return Current.ResolveKeyed<T>(key);
        }

        /// <summary>
        /// 注意释放
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object GetService(Type type)
        {
            return Current.Resolve(type);
        }

        public static object GetService(string key, Type type)
        {
            return Current.ResolveKeyed(key, type);
        }

        #endregion
    }
}
